# -*- coding:utf-8 -*-
import os
import platform
import time
import zipfile
import sys
import json
import hashlib
from pyh import *



ISOTIMEFORMAT='%Y-%m-%d %X'

CONFIG_INI = 'config.ini'
CONFIG_INI_KEY_AAPT_BIN = 'aapt_bin'
CONFIG_INI_KEY_PERMISSIONS = 'permissions'


CURRENT_PATH = os.path.dirname(os.path.abspath(__file__))
CURRENT_PLATFORM = platform.system().lower()
CURRENT_ARCH = platform.architecture()[0].lower()

config_aapt=''
config_permissions = []


class Report(object):
    def __init__(self, title,report_file):
        self.title = '# '+ title + '\n'
        self.reports = [self.title]
        self.fileObject = open(report_file, 'w')

    def setHeader(self,level,report):
        p = ''
        while level > 0:
            p = p + '#'
            level = level - 1
        return '%s %s' % (p,report)
        
    def setItalic(self,report):
        p='*'
        return '%s%s%s' %(p,report,p)

    def setBold(self,report):
        p='**'
        return '%s%s%s' %(p,report,p)

    def setBlock(self,report):
        return '>'+report

    def setDangerous(self, report):
        return self.setItalic(self.setBold(report))

    def addReport(self, report):
        self.reports.append(report +'\n')

    def getReport(self):
        return self.reports

    def write2File(self):
        self.fileObject.writelines(self.getReport())
        self.fileObject.close()

def getFileMD5(filename):
    with open(filename,'rb') as f:
        md5obj = hashlib.md5()
        md5obj.update(f.read())
        hash = md5obj.hexdigest()
        print hash
        return hash

def execShell(shell):
    # if 'linux' in CURRENT_PLATFORM:
    return os.popen(shell)

def unzipCert(zipfilename, unziptodir):
    if not os.path.exists(unziptodir): os.mkdir(unziptodir, 0777)
    zfobj = zipfile.ZipFile(zipfilename)
    for name in zfobj.namelist():
        name = name.replace('\\','/')
        
        if name.endswith('/'):
            pass #os.mkdir(os.path.join(unziptodir, name))
        else:            
            if name.lower().endswith('CERT.RSA'.lower()):
                ext_filename = os.path.join(unziptodir, name)
                ext_dir= os.path.dirname(ext_filename)
                if not os.path.exists(ext_dir) : os.mkdir(ext_dir,0777)
                outfile = open(ext_filename, 'wb')
                outfile.write(zfobj.read(name))
                outfile.close()
                return ext_filename
    return ''


def log(str):
    _str ='%s\n' % str
    print("<<<%s>>> " % str)
    return _str


def loadConfig():
    aapt = ''
    if 'windows' in CURRENT_PLATFORM:
        if '64' in CURRENT_ARCH:
            aapt = os.path.join(CURRENT_PATH, 'aapt/win_x64/aapt.exe')
    elif 'linux' in CURRENT_PLATFORM:
        if '64' in CURRENT_ARCH:
            aapt = os.path.join(CURRENT_PATH, 'aapt/linux_x64/aapt')
    permissions=[]
    file_object = open('%s/%s' % (CURRENT_PATH,CONFIG_INI), 'r')
    lines = file_object.readlines()
    file_object.close()
    jsonString = ''
    for line in lines:
        jsonString = jsonString + line.strip('\r\n')
        # kv = line.split('=')
        # if CONFIG_INI_KEY_AAPT_BIN == kv[0] and aapt.strip() == '':
        #     aapt= kv[1].strip('\r\n')
        # elif CONFIG_INI_KEY_PERMISSION== kv[0]:
        #     permissions.append(kv[1].strip('\r\n'))
    s = json.loads(jsonString)
    if aapt.strip() == '':
        aapt = s[CONFIG_INI_KEY_AAPT_BIN]
    permissions = s[CONFIG_INI_KEY_PERMISSIONS]
    return aapt, permissions

PACKAGE_PREFIX = 'package'
PACKAGE_NAME_KEY = 'name'
PACKAGE_VERSIONCODE_KEY = 'versionCode'
PACKAGE_VERSIONNAME_KEY = 'versionName'
PACKAGE_LABLE_KEY = 'application-label'
PACKAGE_LABLE_ZH_CN_KEY = 'application-label-zh-CN'

def checkApkInfo(report,infos):
    packageName = ''
    versionCode = ''
    versionName = ''
    labelName = ''
    for line in infos:  #按行遍历
        kv = line.split(':')
        if PACKAGE_PREFIX == kv[0]:
            values = kv[1].split(' ')
            for value in values:
                kv = value.split('=')
                if PACKAGE_NAME_KEY == kv[0]:
                    packageName = kv[1].replace('\'','')
                elif PACKAGE_VERSIONCODE_KEY == kv[0]:
                    versionCode = kv[1].replace('\'','')
                elif PACKAGE_VERSIONNAME_KEY == kv[0]:
                    versionName = kv[1].replace('\'','')
        elif PACKAGE_LABLE_ZH_CN_KEY == kv[0]:
            labelName = kv[1].replace('\'','')
        elif PACKAGE_LABLE_KEY == kv[0] and labelName.strip() == '':
            labelName = kv[1].replace('\'','')
    report.addReport(report.setHeader(3,'packageName: %s' % packageName))
    report.addReport(report.setHeader(3,'labelName: %s' % labelName))
    report.addReport(report.setHeader(3,'versionCode: %s' % versionCode))
    report.addReport(report.setHeader(3,'versionName: %s' % versionName))
    return report


PERMISSION_PREFIX1 = 'uses-permission'
PERMISSION_PREFIX2 = 'permission'

def checkPermission(report,infos):
    permissions=[]
    report.addReport(report.setHeader(2,'app use permissions:'))
    for line in infos:  #按行遍历
        kv = line.split(':')
        if PERMISSION_PREFIX1 == kv[0] or PERMISSION_PREFIX2 == kv[0]:
            value = kv[1]
            kv = value.split('=')
            p=kv[1].replace('\'','')
            report.addReport(report.setBlock(report.setHeader(5, p)))
            permissions.append(p)
    report.addReport('')
    report.addReport(report.setHeader(2, report.setDangerous('app use alert permissions:')))
    for _permission in permissions:
        if _permission in config_permissions:
            report.addReport(report.setBlock(report.setHeader(5, report.setDangerous(_permission))))
    return report

SKY_SIGNATURE_SHA1 = 'E724050A4ADA375770BB8F957C4B60DC335DD346'

def checkSignature(report,apkFile,tmpDir):
    cert = unzipCert(apkFile,tmpDir)
    if cert != '':
        # if 'linux' in CURRENT_PLATFORM:
        infos = execShell('%s -printcert -file %s' % ('keytool',cert))
        for line in infos:
            value  =line.strip('\r\n').upper()
            if 'SHA1' in value:
                kv = value.split(': ')
                sha1 = kv[1].replace(':','').upper()
                if SKY_SIGNATURE_SHA1 == sha1:
                    report.addReport(report.setHeader(3, report.setDangerous('useSignature: true')))
                    os.remove(cert)
                    return report
    report.addReport(report.setHeader(3,'useSignature: false'))
    if cert != '':
        os.remove(cert)
    return report

UID_KEY = 'android:sharedUserId'
UID_SYSTEM_UID = 'android.uid.system'
#android:sharedUserId(0x0101000b)="android.uid.system" (Raw: "android.uid.system")
def checkSharedUID(report, apkFile):
    infos = execShell('%s dump xmltree %s AndroidManifest.xml' % (config_aapt, apkFile))
    uid = ''
    useSystemUID = report.setHeader(3, 'useSystemUID: false')
    for line in infos:
        value = line.strip('\r\n')
        if UID_KEY in value:
            kv = value.split('=')
            kv = kv[1].split(' ')
            uid = kv[0].replace('\"', '')
            if uid == UID_SYSTEM_UID:
                useSystemUID = report.setHeader(3, report.setDangerous('useSystemUID: true'))
                
    report.addReport(report.setHeader(3, 'sharedUserId: ' + uid))
    report.addReport(useSystemUID)
    return report
            

def checkApk(root, report, apkFile):
    log('start to check %s' % apkFile)
    infos = []
    # if 'linux' in CURRENT_PLATFORM:
    infos = execShell('%s dump badging %s' % (config_aapt, apkFile))

    _infos = []
    for line in infos:
        _infos.append(line.strip('\r\n'))

    report.addReport(report.setHeader(5,time.strftime(ISOTIMEFORMAT, time.localtime())))
    report.addReport(report.setHeader(5,"md5:" + getFileMD5(apkFile)))
    report = checkApkInfo(report, _infos)
    report = checkSharedUID(report, apkFile)
    report = checkSignature(report, apkFile, root)
    report = checkPermission(report, _infos)

    report.write2File()
    log('check %s complete!' % apkFile)
    

def runCheck(report_dir, root, path):
    if os.path.isdir(path):
        parents = os.listdir(path)
        for parent in parents:
            child = os.path.join(path,parent)
            runCheck(report_dir, root, child)
    elif path.lower().endswith('.apk'):
        file_name = os.path.relpath(path,root)
        file_name = os.path.splitext(file_name)[0] 
        file_name = file_name.replace('/','-')
        file_name = file_name.replace('\\','-')
        report_file =  os.path.join(report_dir, '%s.md' %  file_name)
        report = Report(path, report_file)
        checkApk(root, report, path) 

config_aapt, config_permissions = loadConfig()
path = os.path.abspath(os.curdir)
if len(sys.argv) == 2:
    path = sys.argv[1]

report_dir = ''
root_dir = path
if os.path.isdir(path):
    report_dir = os.path.join(path,'report')
else:
    root_dir = os.path.split(path)[0]
    report_dir = os.path.join(root_dir,'report')
if not os.path.exists(report_dir):
    os.mkdir(report_dir)
log('[acpt]running on %s(%s)' % (CURRENT_PLATFORM,CURRENT_ARCH))
log('[acpt]using aapt %s' % config_aapt)
log('[acpt]check at %s' % root_dir)
log('[acpt]report at %s' % report_dir)

runCheck(report_dir, root_dir, path)

log('[acpt]ALL DONE!!! see report at ' + report_dir)

page = PyH('My wonderful PyH page')
page.addCSS('myStylesheet1.css', 'myStylesheet2.css')
page.addJS('myJavascript1.js', 'myJavascript2.js')
page << h1('My big title',cl='center')
page << div(cl='myCSSclass1 myCSSclass2', id='myDiv1') << p( 'I love PyH!',id='myP1')
mydiv2 = page << div(id='myDiv2')
mydiv2 << h2('A smaller title') + p('Followed by a paragraph.')
page << div(id='myDiv3')
page.myDiv3.attributes['cl'] = 'myCSSclass3'
page.myDiv3 << p('Another paragraph')
page.printOut()